home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.004 / xemacs-1 / xemacs-19.13 / src / doprnt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-08-04  |  20.1 KB  |  756 lines

  1. /* Output like sprintf to a buffer of specified size.
  2.    Also takes args differently: pass one pointer to an array of strings
  3.    in addition to the format string which is separate.
  4.    Copyright (C) 1995 Amdahl Corporation.
  5.    Rewritten by mly to use varargs.h.
  6.    Rewritten from scratch by Ben Wing (February 1995) for Mule; expanded
  7.    to full printf spec.
  8.  
  9. This file is part of XEmacs.
  10.  
  11. XEmacs is free software; you can redistribute it and/or modify it
  12. under the terms of the GNU General Public License as published by the
  13. Free Software Foundation; either version 2, or (at your option) any
  14. later version.
  15.  
  16. XEmacs is distributed in the hope that it will be useful, but WITHOUT
  17. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  18. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  19. for more details.
  20.  
  21. You should have received a copy of the GNU General Public License
  22. along with XEmacs; see the file COPYING.  If not, write to the Free
  23. Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  24.  
  25. /* Synched up with: Mule 2.0, FSF 19.28. */
  26.  
  27. #include <config.h>
  28. #include "lisp.h"
  29.  
  30. #include "buffer.h"
  31. #include "lstream.h"
  32.  
  33. static char *valid_flags = "-+ #0";
  34.  
  35. static char *valid_converters = "diouxXfeEgGcsS";
  36. static char *int_converters = "dic";
  37. static char *unsigned_int_converters = "ouxX";
  38. static char *double_converters = "feEgG";
  39. static char *string_converters = "sS";
  40.  
  41. struct printf_spec
  42. {
  43.   int argnum; /* which argument does this spec want?  This is one-based:
  44.          The first argument given is numbered 1, the second
  45.          is 2, etc.  This is to handle %##$x-type specs. */
  46.   int minwidth;
  47.   int precision;
  48.   int minus_flag:1;
  49.   int plus_flag:1;
  50.   int space_flag:1;
  51.   int number_flag:1;
  52.   int zero_flag:1;
  53.   int h_flag:1;
  54.   int l_flag:1;
  55.   char converter; /* converter character or 0 for dummy marker
  56.              indicating literal text at the end of the
  57.              specification */
  58.   Bytecount text_before; /* position of the first character of the
  59.                 block of literal text before this spec */
  60.   Bytecount text_before_len; /* length of that text */
  61. };
  62.  
  63. union printf_arg
  64. {
  65.   int i;
  66.   unsigned int ui;
  67.   long l;
  68.   unsigned long ul;
  69.   double d;
  70.   Bufbyte *bp;
  71. };
  72.  
  73. /* We maintain a list of all the % specs in the specification,
  74.    along with the offset and length of the block of literal text
  75.    before each spec.  In addition, we have a "dummy" spec that
  76.    represents all the literal text at the end of the specification.
  77.    Its converter is 0. */
  78.  
  79. typedef struct
  80. {
  81.   Dynarr_declare (struct printf_spec);
  82. } printf_spec_dynarr;
  83.  
  84. typedef struct
  85. {
  86.   Dynarr_declare (union printf_arg);
  87. } printf_arg_dynarr;
  88.  
  89. /* Append STRING (of length LEN) to STREAM.  MINLEN is the minimum field
  90.    width.  If MINUS_FLAG is set, left-justify the string in its field;
  91.    otherwise, right-justify.  If ZERO_FLAG is set, pad with 0's; otherwise
  92.    pad with spaces.
  93.  
  94.    Note that MINLEN is a Charcount but LEN is a Bytecount. */
  95.  
  96. static void
  97. doprnt_1 (Lisp_Object stream, CONST Bufbyte *string, Bytecount len,
  98.       Charcount minlen, int minus_flag, int zero_flag)
  99. {
  100.   Charcount cclen;
  101.   Bufbyte pad;
  102.   Lstream *lstr = XLSTREAM (stream);
  103.  
  104.   cclen = bytecount_to_charcount (string, len);
  105.  
  106.   if (zero_flag)
  107.     pad = '0';
  108.   else
  109.     pad = ' ';
  110.  
  111.   /* Padding at beginning to right-justify ... */
  112.   if (minlen > cclen && !minus_flag)
  113.     {
  114.       int to_add = minlen - cclen;
  115.       while (to_add > 0)
  116.     {
  117.       Lstream_putc (lstr, pad);
  118.       to_add--;
  119.     }
  120.     }
  121.   
  122.   {
  123.     /* Simply truncating LEN to the size of the buffer might result in a
  124.        partial character being copied, which is bad bad bad.  So we use
  125.        VALIDATE_CHARPTR_BACKWARD to avoid this. */
  126.     CONST Bufbyte *strend = string + len;
  127.     VALIDATE_CHARPTR_BACKWARD (strend);
  128.     len = strend - string;
  129.   }
  130.   Lstream_write (lstr, string, len);
  131.  
  132.   /* Padding at end to left-justify ... */
  133.   if (minlen > cclen && minus_flag)
  134.     {
  135.       int to_add = minlen - cclen;
  136.       while (to_add > 0)
  137.     {
  138.       Lstream_putc (lstr, pad);
  139.       to_add--;
  140.     }
  141.     }
  142. }
  143.  
  144. static CONST Bufbyte *
  145. parse_off_posnum (CONST Bufbyte *start, CONST Bufbyte *end, int *returned_num)
  146. {
  147.   Bufbyte arg_convert[100];
  148.   REGISTER Bufbyte *arg_ptr = arg_convert;
  149.   
  150.   *returned_num = -1;
  151.   while (start != end && isdigit (*start))
  152.     {
  153.       if (arg_ptr - arg_convert >= sizeof (arg_convert) - 1)
  154.     error ("Format converter number too large");
  155.       *arg_ptr++ = *start++;
  156.     }
  157.   *arg_ptr = '\0';
  158.   if (arg_convert != arg_ptr)
  159.     *returned_num = atoi ((char *) arg_convert);
  160.   return start;
  161. }
  162.  
  163. #define NEXT_ASCII_BYTE(ch)                    \
  164.   do {                                \
  165.     if (fmt == fmt_end)                        \
  166.       error ("Premature end of format string");            \
  167.     ch = *fmt;                            \
  168.     if (ch >= 0200)                        \
  169.       error ("Non-ASCII character in format converter spec");    \
  170.     fmt++;                            \
  171.   } while (0)
  172.  
  173. static printf_spec_dynarr *
  174. parse_doprnt_spec (CONST Bufbyte *format, Bytecount format_length)
  175. {
  176.   CONST Bufbyte *fmt = format;
  177.   CONST Bufbyte *fmt_end = format + format_length;
  178.   printf_spec_dynarr *specs = Dynarr_new (struct printf_spec);
  179.   int prev_argnum = 0;
  180.  
  181.   while (1)
  182.     {
  183.       struct printf_spec spec;
  184.       CONST Bufbyte *text_end;
  185.       Bufbyte ch;
  186.  
  187.       memset (&spec, 0, sizeof (spec));
  188.       if (fmt == fmt_end)
  189.     return specs;
  190.       text_end = (Bufbyte *) memchr (fmt, '%', fmt_end - fmt);
  191.       if (!text_end)
  192.     text_end = fmt_end;
  193.       spec.text_before = fmt - format;
  194.       spec.text_before_len = text_end - fmt;
  195.       fmt = text_end;
  196.       if (fmt != fmt_end)
  197.     {
  198.       fmt++; /* skip over % */
  199.  
  200.       /* A % is special -- no arg number.  According to ANSI specs,
  201.          field width does not apply to %% conversion. */
  202.       if (fmt != fmt_end && *fmt == '%')
  203.         {
  204.           spec.converter = '%';
  205.           Dynarr_add (specs, spec);
  206.           fmt++;
  207.           continue;
  208.         }
  209.  
  210.       /* Is there a field number specifier? */
  211.       {
  212.         CONST Bufbyte *ptr;
  213.         int fieldspec;
  214.  
  215.         ptr = parse_off_posnum (fmt, fmt_end, &fieldspec);
  216.         if (fieldspec > 0 && ptr != fmt_end && *ptr == '$')
  217.           {
  218.         /* There is a format specifier */
  219.         prev_argnum = fieldspec;
  220.         fmt = ptr + 1;
  221.           }
  222.         else
  223.           prev_argnum++;
  224.         spec.argnum = prev_argnum;
  225.       }
  226.  
  227.       /* Parse off any flags */
  228.       NEXT_ASCII_BYTE (ch);
  229.       while (strchr (valid_flags, ch))
  230.         {
  231.           switch (ch)
  232.         {
  233.         case '-': spec.minus_flag = 1; break;
  234.         case '+': spec.plus_flag = 1; break;
  235.         case ' ': spec.space_flag = 1; break;
  236.         case '#': spec.number_flag = 1; break;
  237.         case '0': spec.zero_flag = 1; break;
  238.         default: abort ();
  239.         }
  240.           NEXT_ASCII_BYTE (ch);
  241.         }
  242.       
  243.       /* Parse off the minimum field width */
  244.       fmt--; /* back up */
  245.       fmt = parse_off_posnum (fmt, fmt_end, &spec.minwidth);
  246.       if (spec.minwidth == -1)
  247.         spec.minwidth = 0;
  248.  
  249.       /* Parse off any precision specified */
  250.       NEXT_ASCII_BYTE (ch);
  251.       if (ch == '.')
  252.         {
  253.           fmt = parse_off_posnum (fmt, fmt_end, &spec.precision);
  254.           if (spec.precision == -1)
  255.         spec.precision = 0;
  256.           NEXT_ASCII_BYTE (ch);
  257.         }
  258.       else
  259.         /* No precision specified */
  260.         spec.precision = -1;
  261.  
  262.       /* Parse off h or l flag */
  263.       if (ch == 'h' || ch == 'l')
  264.         {
  265.           if (ch == 'h')
  266.         spec.h_flag = 1;
  267.           else
  268.         spec.l_flag = 1;
  269.           NEXT_ASCII_BYTE (ch);
  270.         }
  271.  
  272.       if (!strchr (valid_converters, ch))
  273.         error ("Invalid converter character %c", ch);
  274.       spec.converter = ch;
  275.     }
  276.  
  277.       if (spec.space_flag && spec.plus_flag)
  278.     spec.space_flag = 0;
  279.       if (spec.zero_flag && spec.space_flag)
  280.     spec.zero_flag = 0;
  281.  
  282.       Dynarr_add (specs, spec);
  283.     }
  284.  
  285.   return specs; /* suppress compiler warning */
  286. }
  287.  
  288. static int
  289. get_args_needed (printf_spec_dynarr *specs)
  290. {
  291.   int args_needed = 0;
  292.   REGISTER int i;
  293.  
  294.   /* Figure out how many args are needed.  This may be less than
  295.      the number of specs because a spec could be %% or could be
  296.      missing (literal text at end of format string) or there
  297.      could be specs where the field number is explicitly given.
  298.      We just look for the maximum argument number that's referenced. */
  299.  
  300.   for (i = 0; i < Dynarr_length (specs); i++)
  301.     {
  302.       char ch = Dynarr_at (specs, i).converter;
  303.       if (ch && ch != '%')
  304.     {
  305.       int argnum = Dynarr_at (specs, i).argnum;
  306.       if (argnum > args_needed)
  307.         args_needed = argnum;
  308.     }
  309.     }
  310.  
  311.   return args_needed;
  312. }
  313.  
  314. static printf_arg_dynarr *
  315. get_doprnt_args (printf_spec_dynarr *specs, va_list vargs)
  316. {
  317.   printf_arg_dynarr *args = Dynarr_new (union printf_arg);
  318.   union printf_arg arg;
  319.   REGISTER int i;
  320.   int args_needed = get_args_needed (specs);
  321.  
  322.   memset (&arg, 0, sizeof (union printf_arg));
  323.   for (i = 1; i <= args_needed; i++)
  324.     {
  325.       int j;
  326.       char ch;
  327.       struct printf_spec *spec = 0;
  328.  
  329.       for (j = 0; j < Dynarr_length (specs); j++)
  330.     {
  331.       spec = Dynarr_atp (specs, j);
  332.       if (spec->argnum == i)
  333.         break;
  334.     }
  335.  
  336.       if (j == Dynarr_length (specs))
  337.     error ("No conversion spec for argument %d", i);
  338.  
  339.       ch = spec->converter;
  340.  
  341.       /* int even if ch == 'c': "the type used in va_arg is supposed to
  342.      match the actual type **after default promotions**." */
  343.  
  344.       if (strchr (int_converters, ch))
  345.     {
  346.       if (spec->h_flag)
  347.         arg.i = va_arg (vargs, short);
  348.       else if (spec->l_flag)
  349.         arg.l = va_arg (vargs, long);
  350.       else
  351.         arg.i = va_arg (vargs, int);
  352.     }
  353.       else if (strchr (unsigned_int_converters, ch))
  354.     {
  355.       if (spec->h_flag)
  356.         arg.ui = va_arg (vargs, unsigned short);
  357.       else if (spec->l_flag)
  358.         arg.ul = va_arg (vargs, unsigned long);
  359.       else
  360.         arg.ui = va_arg (vargs, unsigned int);
  361.     }
  362.       else if (strchr (double_converters, ch))
  363.     arg.d = va_arg (vargs, double);
  364.       else if (strchr (string_converters, ch))
  365.     arg.bp = va_arg (vargs, Bufbyte *);
  366.       else abort ();
  367.  
  368.       Dynarr_add (args, arg);
  369.     }
  370.  
  371.   return args;
  372. }
  373.  
  374. /* Generate output from a format-spec FORMAT, of length FORMAT_LENGTH.
  375.    Output goes in BUFFER, which has room for BUFSIZE bytes.
  376.    If the output does not fit, truncate it to fit.
  377.    Returns the number of bytes stored into BUFFER.
  378.    LARGS or VARGS points to the arguments, and NARGS says how many.
  379.    if LARGS is non-zero, it should be a pointer to NARGS worth of
  380.    Lisp arguments.  Otherwise, VARGS should be a va_list referring
  381.    to the arguments. */
  382.  
  383. static Bytecount
  384. emacs_doprnt_1 (Lisp_Object stream, CONST Bufbyte *format_nonreloc,
  385.         Lisp_Object format_reloc, Bytecount format_length,
  386.         int nargs, 
  387.         /* #### Gag me, gag me, gag me */
  388.         CONST Lisp_Object *largs, va_list vargs)
  389. {
  390.   printf_spec_dynarr *specs = 0;
  391.   printf_arg_dynarr *args = 0;
  392.   REGISTER int i;
  393.   int init_byte_count = Lstream_byte_count (XLSTREAM (stream));
  394.  
  395.   if (!NILP (format_reloc))
  396.     {
  397.       format_nonreloc = string_data (XSTRING (format_reloc));
  398.       format_length = string_length (XSTRING (format_reloc));
  399.     }
  400.   if (format_length < 0)
  401.     format_length = (Bytecount) strlen ((char *) format_nonreloc);
  402.  
  403.   specs = parse_doprnt_spec (format_nonreloc, format_length);
  404.   if (largs)
  405.     {
  406.     /* allow too many args for string, but not too few */
  407.       if (nargs < get_args_needed (specs))
  408.     signal_error (Qwrong_number_of_arguments,
  409.               list3 (Qformat,
  410.                  make_number (nargs),
  411.                  !NILP (format_reloc) ? format_reloc :
  412.                  make_string (format_nonreloc, format_length)));
  413.     }
  414.   else
  415.     {
  416.       args = get_doprnt_args (specs, vargs);
  417.     }
  418.  
  419.   for (i = 0; i < Dynarr_length (specs); i++)
  420.     {
  421.       struct printf_spec *spec = Dynarr_atp (specs, i);
  422.       char ch;
  423.  
  424.       /* Copy the text before */
  425.       if (!NILP (format_reloc)) /* refetch in case of GC below */
  426.     format_nonreloc = string_data (XSTRING (format_reloc));
  427.        doprnt_1 (stream, format_nonreloc + spec->text_before,
  428.          spec->text_before_len, 0, 0, 0);
  429.  
  430.       ch = spec->converter;
  431.  
  432.       if (!ch)
  433.     continue;
  434.  
  435.       if (ch == '%')
  436.     {
  437.       doprnt_1 (stream, (Bufbyte *) &ch, 1, 0, 0, 0);
  438.       continue;
  439.     }
  440.  
  441.       if (largs && (spec->argnum < 1 || spec->argnum > nargs))
  442.     error ("Invalid repositioning argument %d", spec->argnum);
  443.  
  444.       else if (ch == 'S' || ch == 's')
  445.     {
  446.       Bufbyte *string;
  447.       Bytecount string_len;
  448.  
  449.       if (!largs)
  450.         {
  451.           string = Dynarr_at (args, spec->argnum - 1).bp;
  452.           string_len = strlen ((char *) string);
  453.         }
  454.       else
  455.         {
  456.           Lisp_Object obj = largs[spec->argnum - 1];
  457.           struct Lisp_String *ls;
  458.  
  459.           if (ch == 'S')
  460.         {
  461.           /* For `S', prin1 the argument and then treat like
  462.              a string.  */
  463.           ls = XSTRING (Fprin1_to_string (obj, Qnil));
  464.         }
  465.           else if (STRINGP (obj))
  466.         ls = XSTRING (obj);
  467.           else if (SYMBOLP (obj))
  468.         ls = XSYMBOL (obj)->name;
  469.           else
  470.         {
  471.           /* convert to string using princ. */
  472.           ls = XSTRING (Fprin1_to_string (obj, Qt));
  473.         }
  474.           string = string_data (ls);
  475.           string_len = string_length (ls);
  476.         }
  477.  
  478.       if (spec->precision >= 0)
  479.         string_len = min (string_len, spec->precision);
  480.       doprnt_1 (stream, string, string_len, spec->minwidth,
  481.             spec->minus_flag, spec->zero_flag);
  482.     }
  483.  
  484.       else
  485.     {
  486.       /* Must be a number. */
  487.       union printf_arg arg;
  488.  
  489.       if (!largs)
  490.         {
  491.           arg = Dynarr_at (args, spec->argnum - 1);
  492.         }
  493.       else
  494.         {
  495.           Lisp_Object obj = largs[spec->argnum - 1];
  496.           if (!INT_OR_FLOATP (obj))
  497.         {
  498.           error ("format specifier %%%c doesn't match argument type",
  499.              ch);
  500.         }
  501.           else if (strchr (double_converters, ch))
  502.         arg.d = XFLOATINT (obj);
  503.           else
  504.         {
  505.           int val;
  506.  
  507.           if (FLOATP (obj))
  508.             val = XINT (Ftruncate (obj));
  509.           else
  510.             val = XINT (obj);
  511.           if (strchr (unsigned_int_converters, ch))
  512.             {
  513.               if (spec->l_flag)
  514.             arg.ul = (unsigned long) val;
  515.               else
  516.             arg.ui = (unsigned int) val;
  517.             }
  518.           else
  519.             {
  520.               if (spec->l_flag)
  521.             arg.l = (long) val;
  522.               else
  523.             arg.i = val;
  524.             }
  525.         }
  526.         }
  527.  
  528.  
  529.       if (ch == 'c')
  530.         {
  531.           Emchar a;
  532.           Bytecount charlen;
  533.           Bufbyte charbuf[MAX_EMCHAR_LEN];
  534.  
  535.           if (spec->l_flag)
  536.         a = (Emchar) arg.l;
  537.           else
  538.         a = (Emchar) arg.i;
  539.         
  540.           if (!valid_char_p (a))
  541.         error ("invalid character value %d to %%c spec", a);
  542.  
  543.           charlen = emchar_to_charptr (a, charbuf);
  544.           doprnt_1 (stream, charbuf, charlen, spec->minwidth,
  545.             spec->minus_flag, spec->zero_flag);
  546.         }
  547.  
  548.       else
  549.         {
  550.           char text_to_print[500];
  551.           char constructed_spec[100];
  552.  
  553.           /* Partially reconstruct the spec and use sprintf() to
  554.          format the string. */
  555.  
  556.           /* Make sure nothing stupid happens */
  557.           /* DO NOT REMOVE THE (int) CAST!  Incorrect results will
  558.          follow! */
  559.           spec->precision = min (spec->precision,
  560.                      (int) (sizeof (text_to_print) - 50));
  561.  
  562.           constructed_spec[0] = 0;
  563.           strcat (constructed_spec, "%");
  564.           if (spec->plus_flag)
  565.         strcat (constructed_spec, "+");
  566.           if (spec->space_flag)
  567.         strcat (constructed_spec, " ");
  568.           if (spec->number_flag)
  569.         strcat (constructed_spec, "#");
  570.           if (spec->precision >= 0)
  571.         {
  572.           strcat (constructed_spec, ".");
  573.           sprintf (constructed_spec + strlen (constructed_spec), "%d",
  574.                spec->precision);
  575.         }
  576.           sprintf (constructed_spec + strlen (constructed_spec), "%c", ch);
  577.  
  578.           /* sprintf the mofo */
  579.           /* we have to use separate calls to sprintf(), rather than
  580.          a single big conditional, because of the different types
  581.          of the arguments */
  582.           if (strchr (double_converters, ch))
  583.         sprintf (text_to_print, constructed_spec, arg.d);
  584.           else if (strchr (unsigned_int_converters, ch))
  585.         {
  586.           if (spec->l_flag)
  587.             sprintf (text_to_print, constructed_spec, arg.ul);
  588.           else
  589.             sprintf (text_to_print, constructed_spec, arg.ui);
  590.         }
  591.           else
  592.         {
  593.           if (spec->l_flag)
  594.             sprintf (text_to_print, constructed_spec, arg.l);
  595.           else
  596.             sprintf (text_to_print, constructed_spec, arg.i);
  597.         }
  598.  
  599.           doprnt_1 (stream, (Bufbyte *) text_to_print,
  600.             strlen (text_to_print),
  601.             spec->minwidth, spec->minus_flag, spec->zero_flag);
  602.         }
  603.     }
  604.     }
  605.  
  606.   /* #### will not get freed if error */
  607.   if (specs)
  608.     Dynarr_free (specs);
  609.   if (args)
  610.     Dynarr_free (args);
  611.   return Lstream_byte_count (XLSTREAM (stream)) - init_byte_count;
  612. }
  613.  
  614. /* You really don't want to know why this is necessary... */
  615. static Bytecount
  616. emacs_doprnt_2 (Lisp_Object stream, CONST Bufbyte *format_nonreloc,
  617.         Lisp_Object format_reloc, Bytecount format_length, int nargs,
  618.         CONST Lisp_Object *largs, ...)
  619. {
  620.   va_list vargs;
  621.   Bytecount val;
  622.   va_start (vargs, largs);
  623.   val = emacs_doprnt_1 (stream, format_nonreloc, format_reloc,
  624.             format_length, nargs, largs, vargs);
  625.   va_end (vargs);
  626.   return val;
  627. }
  628.  
  629. /*********************** external entry points ***********************/
  630.  
  631. #ifdef I18N3
  632.   /* A note about I18N3 translating: the format string should get
  633.      translated, but not under all circumstances.  When the format
  634.      string is a Lisp string, what should happen is that Fformat()
  635.      should format the untranslated args[0] and return that, and also
  636.      call Fgettext() on args[0] and, if that is different, format it
  637.      and store it in the `string-translatable' property of
  638.      the returned string.  See Fgettext(). */
  639. #endif
  640.  
  641. /* Send formatted output to STREAM.  The format string comes from
  642.    either FORMAT_NONRELOC (of length FORMAT_LENGTH; -1 means use
  643.    strlen() to determine the length) or from FORMAT_RELOC, which
  644.    should be a Lisp string.  Return the number of bytes written
  645.    to the stream.
  646.  
  647.    DO NOT pass the data from a Lisp string as the FORMAT_NONRELOC
  648.    parameter, because this function can cause GC. */
  649.  
  650. Bytecount
  651. emacs_doprnt_c (Lisp_Object stream, CONST Bufbyte *format_nonreloc,
  652.         Lisp_Object format_reloc, Bytecount format_length,
  653.         ...)
  654. {
  655.   int val;
  656.   va_list vargs;
  657.  
  658.   va_start (vargs, format_length);
  659.   val = emacs_doprnt_1 (stream, format_nonreloc, format_reloc,
  660.             format_length, 0, 0, vargs);
  661.   va_end (vargs);
  662.   return val;
  663. }
  664.  
  665. /* Like emacs_doprnt_c but the args come in va_list format. */
  666.  
  667. Bytecount
  668. emacs_doprnt_va (Lisp_Object stream, CONST Bufbyte *format_nonreloc,
  669.          Lisp_Object format_reloc, Bytecount format_length,
  670.          va_list vargs)
  671. {
  672.   return emacs_doprnt_1 (stream, format_nonreloc, format_reloc,
  673.              format_length, 0, 0, vargs);
  674. }
  675.  
  676. /* Like emacs_doprnt_c but the args are Lisp objects instead of
  677.    C arguments.  This causes somewhat different behavior from
  678.    the above two functions (which should act like printf).
  679.    See `format' for a description of this behavior. */
  680.  
  681. Bytecount
  682. emacs_doprnt_lisp (Lisp_Object stream, CONST Bufbyte *format_nonreloc,
  683.            Lisp_Object format_reloc, Bytecount format_length,
  684.            int nargs, CONST Lisp_Object *largs)
  685. {
  686.   return emacs_doprnt_2 (stream, format_nonreloc, format_reloc,
  687.              format_length, nargs, largs);
  688. }
  689.  
  690. /* The following three functions work like the above three but
  691.    return their output as a Lisp string instead of sending it
  692.    to a stream. */
  693.  
  694. Lisp_Object
  695. emacs_doprnt_string_c (CONST Bufbyte *format_nonreloc,
  696.                Lisp_Object format_reloc, Bytecount format_length,
  697.                ...)
  698. {
  699.   va_list vargs;
  700.   Lisp_Object obj;
  701.   Lisp_Object stream = make_resizing_buffer_stream ();
  702.   struct gcpro gcpro1;
  703.  
  704.   GCPRO1 (stream);
  705.   va_start (vargs, format_length);
  706.   emacs_doprnt_1 (stream, format_nonreloc, format_reloc,
  707.           format_length, 0, 0, vargs);
  708.   va_end (vargs);
  709.   Lstream_flush (XLSTREAM (stream));
  710.   obj = make_string (resizing_buffer_stream_ptr (XLSTREAM (stream)),
  711.              Lstream_byte_count (XLSTREAM (stream)));
  712.   UNGCPRO;
  713.   return obj;
  714. }
  715.  
  716. Lisp_Object
  717. emacs_doprnt_string_va (CONST Bufbyte *format_nonreloc,
  718.             Lisp_Object format_reloc, Bytecount format_length,
  719.             va_list vargs)
  720. {
  721.   /* I'm fairly sure that this function cannot actually GC.
  722.      That can only happen when the arguments to emacs_doprnt_1() are
  723.      Lisp objects rather than C args. */
  724.   Lisp_Object obj;
  725.   Lisp_Object stream = make_resizing_buffer_stream ();
  726.   struct gcpro gcpro1;
  727.  
  728.   GCPRO1 (stream);
  729.   emacs_doprnt_1 (stream, format_nonreloc, format_reloc,
  730.           format_length, 0, 0, vargs);
  731.   Lstream_flush (XLSTREAM (stream));
  732.   obj = make_string (resizing_buffer_stream_ptr (XLSTREAM (stream)),
  733.              Lstream_byte_count (XLSTREAM (stream)));
  734.   UNGCPRO;
  735.   return obj;
  736. }
  737.  
  738. Lisp_Object
  739. emacs_doprnt_string_lisp (CONST Bufbyte *format_nonreloc,
  740.               Lisp_Object format_reloc, Bytecount format_length,
  741.               int nargs, CONST Lisp_Object *largs)
  742. {
  743.   Lisp_Object obj;
  744.   Lisp_Object stream = make_resizing_buffer_stream ();
  745.   struct gcpro gcpro1;
  746.  
  747.   GCPRO1 (stream);
  748.   emacs_doprnt_2 (stream, format_nonreloc, format_reloc,
  749.           format_length, nargs, largs);
  750.   Lstream_flush (XLSTREAM (stream));
  751.   obj = make_string (resizing_buffer_stream_ptr (XLSTREAM (stream)),
  752.              Lstream_byte_count (XLSTREAM (stream)));
  753.   UNGCPRO;
  754.   return obj;
  755. }
  756.